﻿/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://git.oschina.net/cblock/embedme
 * Copyright 2014~2017 @ ShenZhen ,China
*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "Tracer.h"
#include "File.h"

/***********************************************
 * 使用Tracer时必须注意:
 * 最大打印长度设为1024,由MAX_PRINT_LEN决定.
 * 如果超出此长度,rint函数会异常退出
 ************************************************/
#define  MAX_PRINT_LEN  		1024

Tracer::Tracer():
m_traceLevel(TRACE_LEVEL_INFO),
m_traceEnble(true),
m_property(NULL),
m_reloadInterval(-1)
{
}

Tracer::~Tracer()
{
    m_mainThread.cancel();
    DEL_OBJ(m_property);
}

/**
 *  \brief  调试信息打印
 *  \param  printLevel 打印级别
 *  \param  format 格式化字串
 *  \return void
 *  \note   none
 */
void Tracer::print(int level,const char* format,...)
{
    char buf[MAX_PRINT_LEN]={0};
    va_list argp;
    va_start(argp,format);

	if ((!m_traceEnble) ||
		(m_traceLevel > level) ||		/* 当前级别大于要打印级别 */
		(m_traceLevel > TRACE_LEVEL_REL))	/* 当前级别大于或等于最高可打印级别 */
	{
 		return;
	}
    write(fileno(stdout),buf,vsnprintf(buf,(MAX_PRINT_LEN)-1,format,argp));
	va_end(argp);
	fflush(stdout);
}

/**
 *  \brief  调低打印级别,打印更多信息
 *  \param  void
 *  \return void
 *  \note   none
 */
void Tracer::printMore()
{
	if (m_traceEnble &&
  	 	(m_traceLevel > TRACE_LEVEL_DBG))
  	{
		m_traceLevel--;
	}
  	printf("Trace Level[%d]-enable=%d\n",m_traceLevel,m_traceEnble);
}

/**
 *  \brief  调高打印级别,打印更少信息
 *  \param  void
 *  \return void
 *  \note   none
 */
void Tracer::printLess()
{
	if (m_traceEnble &&
		(m_traceLevel <= TRACE_LEVEL_REL))
    {
    	m_traceLevel++;
	}
  	printf("Trace Level[%d]-enable=%d\n",m_traceLevel,m_traceEnble);
}

/**
 *  \brief  设置打印级别
 *  \param  level 打印级别
 *  \return void
 *  \note   none
 */
void Tracer::setLevel(int level)
{
    if (level<0 || level>TRACE_LEVEL_REL)
    {
        return;
    }
	m_traceLevel=level;
}

/**
 *  \brief  返回当前打印级别
 *  \param  void
 *  \return it 当前打印级别
 *  \note   none
 */
int Tracer::getLevel()
{
	return m_traceLevel;
}

/**
 *  \brief  打印调试使能
 *  \param  enable 是否使能
 *  \return void
 *  \note   none
 */
void Tracer::setEnable(bool enable)
{
	m_traceEnble=enable;
}

/**
 *  \brief  当前打印时间
 *  \param  void
 *  \return char* 当前时间字符串
 *  \note   none
 */
char* Tracer::currentTime()
{
	time_t timep;
	time(&timep);
	return ctime(&timep);
}

/**
 *  \brief  调试时间桩开始
 *  \param  void
 *  \return void
 *  \note   none
 */
void Tracer::traceTimerBegin()
{
	gettimeofday(&m_startTime,NULL);
}

/**
 *  \brief  调试时间桩结束
 *  \param  void
 *  \return void
 *  \note   none
 */
void Tracer::traceTimerEnd()
{
	gettimeofday(&m_endTime,NULL);
}

/**
 *  \brief  打印调试时间桩的间隔
 *  \param  void
 *  \return void
 *  \note   none
 */
void Tracer::traceTimerDuration()
{
	int sec=m_endTime.tv_sec-m_startTime.tv_sec;
	int usec=m_endTime.tv_usec-m_startTime.tv_usec;
	if(sec<0)
	{
		return;
	}
	if(usec<0)
	{
		sec-=1;
		usec+=1000000;
	}
	printf("Trace duration : %ds.%03dms\n",sec,usec/1000);
	return ;
}

/**
 *  \brief  以16进制字串的格式打印数据
 *  \param  level 打印级别
 *  \param  tag 标识字串
 *  \param  buf 要打印的内存块地址
 *  \param  len 要打印的内存块长度
 *  \return void
 *  \note   none
 */
void Tracer::printHex(int level,const char* tag,const char* buf,int len)
{
	if ((!m_traceEnble) ||
		(level < m_traceLevel) ||
        NULL==tag &&
        NULL==buf ||
		len <=0)
    {
     	return;
    }
	printf("<HEX:%s>(%d)-[",tag,len);
	for(int i=0;i<len;i++)
	{
		printf("%02x ",(unsigned char)(*(buf+i)));
	}
	printf("]\n");
}
/**
 *  \brief  加载属性文件,用于配置调试信息参数
 *  \param  propFileName 属性文件名称
 *  \param  reloadInterval 重新加载属性文件的间隔(单位为sec)
 *  \return void
 *  \note   reloadInterval<=0时,仅调用该函数时去重新加载配置,>0时按实际指定时间间隔刷新.
 */
void Tracer::loadPropertyFile(std::string propFileName,int reloadInterval)
{
    AutoLock lock(&m_propMutex);
    if (propFileName.empty())
    {
        TRACE_ERR_CLASS("Empty Property File Name!\n");
        return;
    }
    m_propFileName = propFileName;
    DEL_OBJ(m_property);
    m_property = NEW_OBJ KVProperty();
    if (m_property->initWithFile(m_propFileName))
    {
        TRACE_REL_CLASS("Tracer Load Property File: %s\n",m_propFileName.c_str());
    }
    else
    {
        TRACE_ERR_CLASS("Read Property File Error!\n");
        DEL_OBJ(m_property);
        return;
    }
    m_reloadInterval = reloadInterval;
    m_mainThread.start(this);/* 多次调用也没关系 */
}

void Tracer::run()
{
    while(1)
    {
        if (m_reloadInterval>0)
        {
            sleep(m_reloadInterval);
            {
                AutoLock lock(&m_propMutex);
                if (m_property!=NULL)
                {
                    int level = (*m_property)["level"].toInt();
                    if (m_traceLevel!=level) setLevel(level);
                }
            }
        }
        else
        {
            sleep(1);
        }
    }
}